package graphgenetics;

import java.util.Random;

public class Population <T extends PopulationMember> {

    private PopulationMember[] population;
    private int size;
    private Random r;
    private double maxRank;

    public Population(int maxSize, double maxRank) {
        population = new PopulationMember[maxSize];
        size = 0;
        this.maxRank = maxRank;
        r = new Random(4321);
    }

    /**
     * Inserts a new member into the population. This will insert it
     * in the appropriate location (by using the comparable interface)
     * so that the list remains sorted.
     * @param member The population member to add
     * @return the index where it was put. 
     */
    public int insert(T member) {
        if (member.getRank() > maxRank) {
            return -1;
        }

        int index = size;
        if (index < population.length) {
            // Population is not full, add something
            size++;
            population[index] = member;
        }
        // Population is full, add if greater than last
        else if (member.compareTo(population[index-1]) > 0) {
            // It is greater than last, add it to last
            population[--index] = member;
        }
        else {
            // It is not greater than last
            return -1; // member not added
        }

        // Sort the members
        T temp;
        while (index > 0) {
            // Does n need to be swapped with n-1?
            if ( population[index].compareTo(population[index-1]) > 0 ) {
                // Swap
                temp = (T) population[index-1];
                population[index-1] = population[index];
                population[index] = temp;
            }
            else {
                // No more swapping needed
                break;
            }

            index--;
        }
        
        return index;
    }

    /**
     * Returns the current size
     * (the number of members)
     * of the population
     * @return the size of the population
     */
    public int getCurrentSize() {
        return size;
    }

    /**
     * Returns the array that stores the population.
     * For some reason casting it to the type <T> stored
     * in the array doesn't work right.
     * @return the population
     */
    public PopulationMember[] getPopulation() {
        return population;
    }

    /**
     * Returns the first (best) population member
     * @return the first populatin member
     */
    public T getFirst() {
        return (T) population[0];
    }

    /**
     * Returns the last (worst) population member
     * @return the last population member
     */
    public T getLast() {
        return (T) population[size - 1];
    }

    /**
     * Gets a random member from the population
     * @return a population member
     */
    public T getRandom() {
        int index = Math.min(
                r.nextInt(size),
                r.nextInt(size + 1));
        return (T) population[index];
    }
    
}
